<template>
  <div>
    <div class="container" v-show="showCut">
      <div class="origin-img-container" id="container" ref="containerRef">
        <img :src="imgsrc" ref="targetImgRef" class="img" style="cursor:move" id="targetImg" />
        <div class="cub cub1" id="cub1" ref="cub1"></div>
        <div class="cub cub2" id="cub2" ref="cub2"></div>
        <div class="cut-container" ref="cutContainer"></div>
      </div>
    </div>
  </div>
</template>

<script lang='ts'>
import { defineComponent, nextTick, onMounted, ref } from 'vue'

export default defineComponent({
  name: 'PicCut',
  props: {
    width: {
      type: [String, Number],
      default: '100px'
    },
    height: {
      type: [String, Number],
      default: '100px'
    },
    // 图片资源，必输
    imgsrc: {
      type: String,
      required: true
    },
    maxScale: {
      type: Number,
      default: 2
    },
    minScale: {
      type: Number,
      default: 0.1
    },
    showCut: {
      type: [String, Boolean],
      default: false
    }
  },
  watch: {
    showCut: function (value) {
      if (value) {
        console.log('showCut ', this.showCut)
        this.resetCutContainer()
      }
    }
  },
  setup (props) {
    // 展示图片的ref
    const cub1 = ref()
    const cub2 = ref()
    const targetImgRef = ref()
    const cutContainer = ref()
    const containerRef = ref()

    // 创建截图容器
    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')

    // 获取当前设备支持的滚动模式
    const support =
        'onwheel' in document.createElement('div')
          ? 'wheel'
          : (document as any).onmousewheel !== undefined
            ? 'mousewheel'
            : 'DOMMouseScroll'
    const originImgUrl = ref(props.imgsrc)
    const base64CutImgData = ref('')

    // 可配置参数
    const mul = 2
    const min = 0.1
    const scaleStep = 2
    const rateBase = 10000
    let scaleDelt = 10000
    let scaleRate = 1
    let trueImgX = 0
    let trueImgY = 0

    let mousedownX = 0
    let mousedownY = 0

    // 让截图框基于控制点生成
    const resetCutContainer = () => {
      const htmlCub1 = cub1.value
      const htmlCub2 = cub2.value
      const cub1X = htmlCub1.offsetLeft
      const cub1Y = htmlCub1.offsetTop

      const cub2X = htmlCub2.offsetLeft
      const cub2Y = htmlCub2.offsetTop
      const htmlCutContainer = cutContainer.value
      htmlCutContainer.style.left = cub1X + 3 + 'px'
      htmlCutContainer.style.top = cub1Y + 3 + 'px'

      htmlCutContainer.style.width = cub2X - cub1X - 1 + 'px'
      htmlCutContainer.style.height = cub2Y - cub1Y - 1 + 'px'
    }

    // 使元素移动的方法
    const itemMove = (ele: HTMLElement, baseEle: HTMLElement | null, moveCb: Function | null, upCb: Function | null) => {
      console.log(ele)
      let draging = false
      if (!ele) return
      // 对图片的操作---start
      ele.addEventListener('mousedown', (e) => {
        e.preventDefault()
        draging = true
        // 第二次按住鼠标时，坐标与mousemove的一致，会导致图片回到左上角
        mousedownX = e.clientX - ele.offsetLeft
        mousedownY = e.clientY - ele.offsetTop
      })
      ele.addEventListener('mouseup', (e) => {
        draging = false
        if (upCb) upCb(e)
      })
      const moveEle = baseEle || ele
      moveEle.addEventListener('mousemove', (e: MouseEvent) => {
        if (draging) {
          ele.style.left = e.clientX - mousedownX + 'px'
          ele.style.top = e.clientY - mousedownY + 'px'
          if (moveCb) {
            moveCb(e)
          }
        }
      })
    }

    // 要以大容器作为mousemove监听
    const cubMove = () => {
      // 让截图框基于控制点生成
      resetCutContainer()
    }
    const getTrueAix = () => {
      // 获取图片放大后的位置
      const targetImg = targetImgRef.value
      const x1 = targetImg.offsetLeft
      const y1 = targetImg.offsetTop
      trueImgX = x1 + targetImg.offsetWidth / 2 * (1 - scaleRate)
      trueImgY = y1 + targetImg.offsetHeight / 2 * (1 - scaleRate)
      console.log('trueImgX: ', trueImgX, 'trueImgY: ', trueImgY)
    }
    const getBase64ByImageData = (content: ImageData, width: number, height: number) => {
      const nCanvas = document.createElement('canvas')
      const nCtx = nCanvas.getContext('2d')
      if (!nCtx) return
      nCanvas.width = width
      nCanvas.height = height
      nCtx.putImageData(content, 0, 0)
      return nCanvas.toDataURL('image/png')
    }
    const getCutPic = () => {
      const image = new Image()
      image.onload = () => {
        if (!ctx) {
          return
        }
        //  获取原图高度和宽度
        const height = image.height
        const width = image.width
        const htmlCub1 = cub1.value
        const htmlCub2 = cub2.value
        canvas.height = height
        canvas.width = width
        ctx.drawImage(image, 0, 0, width, height)

        getTrueAix()
        const offW = htmlCub2.offsetLeft - htmlCub1.offsetLeft
        const offH = htmlCub2.offsetTop - htmlCub1.offsetTop
        // 获取截图后的像素点阵
        // 是以图片的坐标为准的
        const offX = htmlCub1.offsetLeft - trueImgX
        const offY = htmlCub1.offsetTop - trueImgY
        const scaleRateReverse = 1 / scaleRate
        const cutImg = ctx.getImageData(offX * scaleRateReverse, offY * scaleRateReverse, offW * scaleRateReverse, offH * scaleRateReverse)
        const cutImage = getBase64ByImageData(cutImg, offW, offH)
        base64CutImgData.value = cutImage as string
      }
    }
    const getImageDataBase64 = () => {
      getCutPic()
      return base64CutImgData.value
    }
    const scaleFun = (e: any) => {
      e.preventDefault()
      if (e.deltaY > 0 && scaleDelt < rateBase * mul) {
        scaleDelt += e.deltaY * scaleStep
      } else if (e.deltaY < 0 && scaleDelt > rateBase * min) {
        scaleDelt += e.deltaY * scaleStep
      } else {
        return
      }
      scaleRate = scaleDelt / rateBase
      if (!targetImgRef.value) return
      targetImgRef.value.style.transform = `scale(${scaleRate},${scaleRate})`
    }

    nextTick(() => {
      resetCutContainer()
      itemMove(targetImgRef.value, null, null, null)
      itemMove(cub1.value, containerRef.value, cubMove, getCutPic)
      itemMove(cub2.value, containerRef.value, cubMove, getCutPic)
      cutContainer.value.style.pointerEvents = 'none'
      window.addEventListener(support, scaleFun, { passive: false })
    })

    return {
      targetImgRef,
      originImgUrl,
      cutContainer,
      cub1,
      cub2,
      containerRef,
      getImageDataBase64,
      resetCutContainer
    }
  }
})
</script>

 <style scoped>
.origin-img-container {
  width: 500px;
  height: 500px;
  border: slategrey 1px solid;
  margin-right: 100px;
  overflow: hidden;
  position: relative;
  background-color: darkgrey;
}

.prieview-img-container {
  width: 100px;
  height: 100px;
  border: slategrey 1px solid;
}

.hide-item {
  display: none;
}

.img {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;
}

.container {
  display: flex;
  justify-content: center;
  align-items: center;
}

.cut-container {
  width: 100px;
  height: 100px;
  border: white 2px solid;
  box-shadow: 1px 1px 2px 2px black;
  position: absolute;
  left: 100px;
  top: 100px;
  z-index: 10;
}

.cub {
  width: 10px;
  height: 10px;
  background-color: white;
  position: absolute;
  box-shadow: 1px 1px 2px 2px black;
}

.cub:hover {
  transform: scale(1.2, 1.2);
}

.cub1 {
  top: 5px;
  left: 5px;
  z-index: 11;
}

.cub2 {
  top: 95px;
  left: 95px;
  z-index: 11;
}
</style>
